<?php
class CommonUtil{

	//js openssl 私钥，用于与前端解密
	private static $_js_private_key = '-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDKwzrDzssZmKuw4bj/DDI0sQ6l9FJSlazZS+/FkmxHdyURMnUp
eQfLurMt7k7Ji97ntPEfisBXFCl/5fjXVBAdObIVHMqO2/mO6GINNNQpymLPbXi0
QbaRUJUeaBM7/mIrfHvrfL7SCm3tAByGDsLoQty8CcuR3T/7Vmomu1SkIQIDAQAB
AoGBALaGkLv7yDE+kjAkwlg2Lmvoh3s1OXZGbtcd2LZOXVLoGmIkvfubjD0F0I6k
XCBq3TpQVE9EpGi/KayM5TlR3z4VENch53S2tJSpZyQZhvpBLV2auiwxwn4dUtOo
qF2OIOoGQHFQMALyL9py/7euiT/V38AHBd1/8tVh+2ikyNbRAkEA8EMtt9+9Zzmz
WOYRLJi5WGiSZP1tUs/R4ctTnrtlCFbs3aqIWq/aP9aQ3F9K60drO02yb5L8k6aD
dgFgMi6r3wJBANgLPQ6W0NbUL4IaU67ConwvZCNnRN41oup0HPmCTY0pW8iwnnCG
MprmLQCvjzB2IdJcanpPeZPi72TkhTPmr/8CQEUib4NbZDrRxaOtAAAfKiYgYQ+i
RNTxa+lXAobIUXgm2x2ltnqx41E/QovG993fvSFhaBjm6LrrzSQlnTKTb20CQQCF
6hlzpJpYv3efTpBWgEDVd067/zQaBOcyKr0XD+TgPiWtdYUQPK67gzeb+DZqlJ8M
VMqPfBnhSEaZpGjIrhKjAkAHAQoyPNNx/8R077TQvRSPXVjXFnhQndZJwSfxpzVL
2VyJuolHEAIANI9bVBGvXR4WqiFZGqScef9a+Ixfrz2L
-----END RSA PRIVATE KEY-----';

	//js openssl 公钥
	private static $_js_public_key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKwzrDzssZmKuw4bj/DDI0sQ6l
9FJSlazZS+/FkmxHdyURMnUpeQfLurMt7k7Ji97ntPEfisBXFCl/5fjXVBAdObIV
HMqO2/mO6GINNNQpymLPbXi0QbaRUJUeaBM7/mIrfHvrfL7SCm3tAByGDsLoQty8
CcuR3T/7Vmomu1SkIQIDAQAB
-----END PUBLIC KEY-----';

	//js openssl 模数，用于rsa.js生成公钥 (生成模数命令：rsa -in private_key.pem -noout -modulus)
	private static $_js_openssl_modulus = 'CAC33AC3CECB1998ABB0E1B8FF0C3234B10EA5F4525295ACD94BEFC5926C477725113275297907CBBAB32DEE4EC98BDEE7B4F11F8AC05714297FE5F8D754101D39B2151CCA8EDBF98EE8620D34D429CA62CF6D78B441B69150951E68133BFE622B7C7BEB7CBED20A6DED001C860EC2E842DCBC09CB91DD3FFB566A26BB54A421';

	public static function encodePassword($password){
		$p = md5($password);
		return md5(substr($p, 16, 8).substr($p, 0, 8).substr($p, 24, 8).substr($p, 8, 8));
	}
	
	public static function calculateSign($params, $key){
		if(!is_array($params) || empty($key)){
			return false;
		}
		if(isset($params['sign'])){
			unset($params['sign']);
		}
		
		ksort($params);//对参数字母排序
		reset($params);
		
		return md5(urldecode(http_build_query($params))."&{$key}");
	}
	
	public static function fastExit($msg){
		if(function_exists('fastcgi_finish_request')){
			if($msg){
				echo $msg;
			}
			try{
				fastcgi_finish_request();
				return true;
			}catch(Exception $e){
				//
				return false;
			}
		}
		return false;
	}
	
	/**
	 * 规范化cps分成比例，验证格式
	 * @param string $ratio
	 */
	public static function standardCpsRatio($ratio){
		if(empty($ratio)){
			return false;
		}
		
		$source = $ratio = str_replace(' ', '', str_replace('，', ',', $ratio));
		if(strpos($ratio, '|') === false){
			//转换格式
			$ratio = "0|-1|{$ratio}";
		}
		
		//按照格式验证：0|x|r1,x|xx|r2,xx|-1|r3
		$list = explode(',', $ratio);
		$len = count($list);
		foreach($list as $k=>$v){
			if(empty($v)){
				return false;
			}
			
			list($min, $max, $r) = explode('|', $v);
			$min = floatval($min);
			
			$r = floatval($r);
			if($r<0 || $r >= 1){
				return false;
			}
			
			//最初
			if($k == 0 && $min != 0){
				return false;
			}
			
			//最后
			if($k == ($len - 1) && $max != -1){
				return false;
			}
			if($k != ($len - 1) && ($min >= $max || $min < 0)){
				return false;
			}
			
			//验证是否连续区间
			if($k != 0 && $min != $last){
				return false;
			}
			
			$last = $max = floatval($max);
		}
		
		return $source;
	}
	
	/**
	 * 解析cps分成比例
	 * @param string $ratio
	 * @return array 分成比例二维数组
	 */
	public static function decompressCpsRatio($ratio){
		$ratio = self::standardCpsRatio($ratio);
		if(!$ratio){
			return false;
		}
		
		if(strpos($ratio, '|') === false){
			//转换格式
			$ratio = "0|-1|{$ratio}";
		}
		
		//按照格式验证：0|x|r1,x|xx|r2,xx|-1|r3
		$list = explode(',', $ratio);
		$ratioList = array();
		foreach($list as $k=>$v){
			list($min, $max, $r) = explode('|', $v);
			$ratioList[] = array('min' => $min, 'max' => $max, 'ratio' => $r);
		}
		
		return $ratioList;
	}
	
	/**
	 * 验证cps结算日期是否为结算周期，日期格式 xxx-xx-xx
	 * @param int $ratioType
	 * @param string $startTime
	 * @param string $endTime
	 */
	public static function validateCpsSettlePeriod($ratioType, $startTime, $endTime){
		if(!key_exists($ratioType, DataDefine::$channelRatioList)){
			return false;
		}
		$time = time();
		$curDayStart = strtotime(date('Y-m-d', $time));
		
		$startTime = strtotime(date('Y-m-d', strtotime($startTime)));
		$endTime = strtotime(date('Y-m-d', strtotime($endTime)));
		
		if(empty($startTime) || empty($endTime) || $startTime < 1440691200 || $endTime < $startTime || $endTime >= $curDayStart){
			return false;
		}
		
		switch($ratioType){
			//固定比例
			case 0:
				break;
			//按周阶梯
			case 1:
				//验证是否周一和周日
				if(date('w', $startTime) !== '1' || date('w', $endTime) !== '0'){
					return false;
				}
				break;
			//按月阶梯
			case 2:
				//验证是否月初月底
				if(strtotime(date('Y-m-01', $startTime)) != $startTime){
					return false;
				}
				//加一天仍同月则证明不是月底
				if(date('Ym', $endTime) == date('Ym', $endTime + 86400)){
					return false;
				}
				break;
			default:
				return false;
		}
		return true;
	}
	
	/**
	 * 验证游戏结算日期是否为结算周期，日期格式 xxx-xx-xx
	 * 游戏按月结算且因cps按周阶梯比例问题导致游戏必须在次月6天后才能结算
	 * @param string $startTime
	 * @param string $endTime
	 */
	public static function validateAppSettlePeriod($startTime, $endTime){
		$time = time();
		//今天开始时间戳
		$curDayStart = strtotime(date('Y-m-d', $time));
		//本月开始时间戳
		$curMonthStart = strtotime(date('Y-m-01', $time));
		
		$startTime = strtotime(date('Y-m-d', strtotime($startTime)));
		$endTime = strtotime(date('Y-m-d', strtotime($endTime)));
		
		//结算截止时间不能本月开始时间，即只能历史月份结算
		if(empty($startTime) || empty($endTime) || $startTime < 1440691200 || $endTime <= $startTime || $endTime >= $curMonthStart){
			return false;
		}
		
		//验证是否月初月底
		if(strtotime(date('Y-m-01', $startTime)) != $startTime){
			return false;
		}
		//加一天仍同月则证明不是月底
		if(date('Ym', $endTime) == date('Ym', $endTime + 86400)){
			return false;
		}
		
		//必须本月首个周末后才能进行上月结算，从月底星期计算下个周末时间
		$w = date('w', $endTime);
		//非周日
		if($w > 0){
			$nextMondayTime = strtotime('next monday', $endTime);
			//当前时间小于首个周末时间
			if($curDayStart < $nextMondayTime){
				return false;
			}
		}
		
		return true;
	}

	public static function validateAppRatio($ratioType, $ratio, $ratioOther = null){
		if(!key_exists($ratioType, DataDefine::$appRatioList)){
			return false;
		}
		
		$ratio = floatval($ratio);
		
		switch($ratioType){
			case 1:
				if(empty($ratio) || $ratio >= 1 || $ratio <= 0){
					return false;
				}
				$ratioOther = floatval($ratioOther);
				if(empty($ratioOther) || $ratioOther >= 1 || $ratioOther <= 0){
					return false;
				}
				break;
			case 2:
				if(empty($ratio) || $ratio >= 1 || $ratio <= 0){
					return false;
				}
				break;
			default:
				return false;
		}
		return true;
	}

	//js rsa 解密(16进制)
	public static function jsDeCrypt($hex_encrypt_data) {
		$private_key = self::$_js_private_key;
		$encrypt_data = pack("H*", $hex_encrypt_data);//对十六进制数据进行转换
		openssl_private_decrypt($encrypt_data, $decrypt_data, $private_key);
		return $decrypt_data;
	}

	/**
	 * 排序，二维数组排序
	 * @param
	 * @param $keys
	 * @param string $type
	 * @return array|string
	 */
	public static function sortByFeild($array,$keys,$type='asc'){
		if (count($array) <= 1) {
			return $array;
		}
		if(!isset($array) || !is_array($array) || empty($array)){
			return '';
		}
		if(!isset($keys) || trim($keys)==''){
			return '';
		}
		if(!isset($type) || $type=='' || !in_array(strtolower($type),array('asc','desc'))){
			return '';
		}
		$keysvalue=array();
		foreach($array as $key=>$val){
			$val[$keys] = str_replace('-','',$val[$keys]);
			$val[$keys] = str_replace(' ','',$val[$keys]);
			$val[$keys] = str_replace(':','',$val[$keys]);
			$keysvalue[] =$val[$keys];
		}
		asort($keysvalue); //key值排序
		reset($keysvalue); //指针重新指向数组第一个
		foreach($keysvalue as $key=>$vals) {
			$keysort[] = $key;
		}

		$keysvalue = array();
		$count=count($keysort);
		if(strtolower($type) != 'asc'){
			for($i=$count-1; $i>=0; $i--) {
				$keysvalue[] = $array[$keysort[$i]];
			}
		}else{
			for($i=0; $i<$count; $i++){
				$keysvalue[] = $array[$keysort[$i]];
			}
		}
		return $keysvalue;
	}
	
	/**
	 * 提取数组中某一个键的值，返回一维数组
	 * @param $data array 数据源
	 * @param $element string 键值
	 * @return mixed aray | bool
	 * @author caisiming
	 */
	public static function extractArrayValue($data = array(), $element = ''){
		if (empty($element) || !is_array($data)) {
			return false;
		}

		if (empty($data)) {
			return array();
		}

		foreach ($data as $key => $value) {
			$data[$key] = $value[$element];
		}
		return $data;
	}

	/**
	 * 验证用户访问同一接口的时间间隔,防止接口被恶意调用
	 * @return bool
	 * @author caisiming
	 */
	public static function checkAPIInterval($interval = 2){
		$time = time();
		if (SIGNIP === NOWIP && ($time - LASTREQUESTTIME < $interval)) {
			return false;
		}
		return true;
	}

	/**
	 * 渠道管理平台前台提示信息
	 * @param @msg 提示信息
	 * @author caisiming 20170601
	 */
	public static function frontAlert($msg = "服务器出错！"){
		echo "<script type='text/javascript'>alert('{$msg}')</script>";
	}

	/**
	 * @param array $data 二维数组
	 * @param string key $key 数组键值
	 * @return array $data 键值的数组集合
	 */
	public static function extractArrayKey($data = array()){
		if (!is_array($data)) {
			return false;
		}

		if (empty($data)) {
			return array();
		}

		$keys = array();
		foreach ($data as $key => $value) {
			$keys = array_merge($keys, array_keys($value));
		}
		return $keys;
	}

	/**
	 * [operateFlag 生成一个操作签名，以防客户端篡改明文字段跳过验证，使表单提交前后幂等]
	 * @param  [type] $client [客户端标识,userid，imei，imac均可]
	 * @param  [type] $opname  [操作名称]
	 * @param  [type] $opval [操作的当前状态]
	 * @return [type]          [description]
	 */
	public static function operateFlag($client, $opname, $opval) {
		$key = $client . '_' . $opname . '_' . $opval;
		return self::encodePassword($key);
	}

    public static function checkIpLimit($ip = null){
        if(empty($ip)){
            $ip = IP::getIP();
        }

        $params['r'] = 'dispatch/index';
        $params['cmd'] = '40101';
        $params['clientip'] = $ip;
        $params['sign'] = CommonUtil::calculateSign($params, '4704fb0c97a#d1a4()da14%0d519d63*6');

        $res = HttpUtil::curlPostJson('http://api.inner.bbbtgo.com/index.php', http_build_query($params));

        if(empty($res)){
            return false;
        }

        if(!isset($res[0]['code']) || $res[0]['code'] != 1){
            return false;
        }

        //1即需要屏蔽ip显示处理
        return $res[0]['data']['state'] == 1 ? true : false;
    }

	public static function logRequest($str){

		$time = time();
		$dir = APP_ROOT.'/../suqulog/god/'.date('Ym', $time);

		if(!file_exists($dir) || !is_dir($dir)){
			mkdir($dir, 0777, true);
		}

		$ip = IP::getIP();
		$data = date('Y-m-d H:i:s', $time)."\t{$ip}\t{$str}\n";
		$file = $dir.'/'.date('Ymd', $time).'.log';

		file_put_contents($file, $data, FILE_APPEND);
	}

    public static  function date(){
        $today = date('Y-m-d');
        $todayInt = strtotime($today);

        $yestodayInt = strtotime('-1 day');
        $yestoday = date('Y-m-d',$yestodayInt);
        $yestodayInt = strtotime($yestoday);

        $thisWeekStartInt = time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600;
        $thisWeekStart = date('Y-m-d',$thisWeekStartInt);
        $thisWeekStartInt = strtotime($thisWeekStart);
        $thisWeekEnd = date('Y-m-d',(time() + (7 - (date('w') == 0 ? 7 : date('w'))) * 24 * 3600));

        $thisMonthStartInt = time();
        $thisMonthStart = date('Y-m-01',$thisMonthStartInt);
        $thisMonthStartInt = strtotime($thisMonthStart);
        $thisMonthEnd = date('Y-m-d',(strtotime(date('Y-m', time()) . '-' . date('t', time()) . ' 00:00:00')));

        $date = array(
            'today' => array($today,$today,$todayInt,($todayInt + (24 * 3600 -1))),
            'yestoday' => array($yestoday,$yestoday,$yestodayInt,($yestodayInt + (24 * 3600 -1))),
            'thisWeek' => array($thisWeekStart,$thisWeekEnd,$thisWeekStartInt,($thisWeekStartInt + (7 * 24 * 3600 - 1))),
            'thisMonth' => array($thisMonthStart,$thisMonthEnd,$thisMonthStartInt,($thisMonthStartInt + (30 * 24 * 3600 -1)))
        );
        return $date;
    }

    public static function arrayToMapS(&$array,$extKey=array()){
        if(empty($array) || !is_array($array) || !is_array($array[0]) || empty($extKey)){
            return false;
        }

        $val="";
        $ar=array();
        foreach($extKey as $key){
            $val.='$v[\''.$key.'\']';
            array_push($ar,'$v[\''.$key.'\']');
        }
        $map = array();
        foreach($array as $v){
            $data=self::_setKey($v,$extKey);
            $key = str_replace($ar,$data,$val);
            $map[$key] = $v;
        }
        return $map;
    }

    public static function _setKey($val,$extKey){
        $resData=array();
        foreach($extKey as $key){
            array_push($resData,$val[$key]);
        }

        return $resData;
    }

    /**
     * 文本内容处理，防止用户恶意攻击
     * @param $content
     */
    public static function safe_html($text, $tags = null){
        $text = trim($text);
        // 完全过滤注释
        $text = preg_replace('/<!--?.*-->/', '', $text);
        // 完全过滤动态代码
        $text = preg_replace('/<\?|\?' . '>/', '', $text);
        // 完全过滤js
        $text = preg_replace('/<script?.*\/script>/', '', $text);

        $text = str_replace('[', '&#091;', $text);
        $text = str_replace(']', '&#093;', $text);
        $text = str_replace('|', '&#124;', $text);
        // 过滤换行符
        $text = preg_replace('/\r?\n/', '', $text);
        // br
        $text = preg_replace('/<br(\s\/)?' . '>/i', '[br]', $text);
        $text = preg_replace('/<p(\s\/)?' . '>/i', '[br]', $text);
        $text = preg_replace('/(\[br\]\s*){10,}/i', '[br]', $text);
        // 过滤危险的属性，如：过滤on事件lang js
        while(preg_match('/(<[^><]+)( lang|on|action|background|codebase|dynsrc|lowsrc)[^><]+/i', $text, $mat)){
            $text = str_replace($mat[0], $mat[1], $text);
        }
        while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i', $text, $mat)){
            $text = str_replace($mat[0], $mat[1] . $mat[3], $text);
        }
        if(empty($tags)){
            $tags = 'table|td|th|tr|i|b|u|strong|img|p|br|div|strong|em|ul|ol|li|dl|dd|dt|a';
        }
        // 允许的HTML标签
        $text = preg_replace('/<(' . $tags . ')( [^><\[\]]*)>/i', '[\1\2]', $text);
        $text = preg_replace('/<\/(' . $tags . ')>/Ui', '[/\1]', $text);
        // 过滤多余html
        $text = preg_replace('/<\/?(html|head|meta|link|base|basefont|body|bgsound|title|style|script|form|iframe|frame|frameset|applet|id|ilayer|layer|name|script|style|xml)[^><]*>/i', '', $text);
        // 过滤合法的html标签
        while(preg_match('/<([a-z]+)[^><\[\]]*>[^><]*<\/\1>/i', $text, $mat)){
            $text = str_replace($mat[0], str_replace('>', ']', str_replace('<', '[', $mat[0])), $text);
        }
        // 转换引号
        while(preg_match('/(\[[^\[\]]*=\s*)(\"|\')([^\2=\[\]]+)\2([^\[\]]*\])/i', $text, $mat)){
            $text = str_replace($mat[0], $mat[1] . '|' . $mat[3] . '|' . $mat[4], $text);
        }
        // 过滤错误的单个引号
        while(preg_match('/\[[^\[\]]*(\"|\')[^\[\]]*\]/i', $text, $mat)){
            $text = str_replace($mat[0], str_replace($mat[1], '', $mat[0]), $text);
        }
        // 转换其它所有不合法的 < >
        $text = str_replace('<', '&lt;', $text);
        $text = str_replace('>', '&gt;', $text);
        $text = str_replace('"', '&quot;', $text);
        // 反转换
        $text = str_replace('[', '<', $text);
        $text = str_replace(']', '>', $text);
        $text = str_replace('|', '"', $text);
        // 过滤多余空格
        $text = str_replace('  ', ' ', $text);
        return $text;
    }
}